/**********************************************************************************\
** 文件名称: VS1838.h
** 创建人员: YCG
** 创建日期: 2017-11-1
** 文档描述:
** 版本代号: V0.1
** 版本说明: 初始版本
  \********************************************************************************/
#include "VS1838.h"
#include "uart.h"
IR_struct IR1 = {0};

IRCode_struct const IRCode[2] = {
    {
        "NEC",                      //类型名称
        IR_NEC,                        //类型
        32,                 //BitNum;              //位数
        SET_RANG(90, 15),    //StartLowTime;        //起始低电平时间    时间间隔大于它
        SET_RANG(45, 10),    //StartHighTime;       //起始高电平时间    时间间隔大于它
        SET_RANG(22, 5),    //ReStartHighTime;     //起始高电平时间    时间间隔大于它
        SET_RANG(5, 3),     //BitLowTime;          //位起始低电平时间  时间间隔小于它
        SET_RANG(6, 5),     //Bit0Time;            //信号0电平时间     时间间隔小于它
        SET_RANG(16, 5),    //Bit1Time;            //信号1电平时间     时间间隔小于它
        SET_RANG(0, 0),     //EndTime;             //结束电平时间
        SET_RANG(1000, 200) //Ctime;
    },
    {
        "KANGJIA",                      //类型名称
        IR_KANGJIA,                        //类型
        16,                 //BitNum;              //位数
        SET_RANG(30, 5),   //StartLowTime;        //起始低电平时间    时间间隔大于它
        SET_RANG(30, 4),   //StartHighTime;       //起始高电平时间    时间间隔大于它
        SET_RANG(22, 2),    //ReStartHighTime;     //起始高电平时间    时间间隔大于它
        SET_RANG(5, 3),     //BitLowTime;          //位起始低电平时间  时间间隔小于它
        SET_RANG(15, 5),     //Bit0Time;            //信号0电平时间     时间间隔小于它
        SET_RANG(25, 5),     //Bit1Time;            //信号1电平时间     时间间隔小于它
        SET_RANG(40, 5),     //EndTime;             //结束电平时间
        SET_RANG(700, 700)     //Ctime;
    }
};

/*******************************************************************************
** 函数名称: vs_init
** 功能描述: IR中断初始化
** 参数说明: None
** 返回说明: None
** 创建人员: YCG
** 创建日期: 2018-11-17
********************************************************************************/
void IrInit(IR_struct* IR, GPIO_TypeDef * Port, uint32_t Pin, IR_CallBack deal)
{
    IR->Port = Port;     //初始化接收端口
    IR->Pin = Pin;       //初始化接收引脚
    IR->DatDeal = deal;  //接收完成时的回调函数
	  VS1838_Printf("%s\r\n IR0X%08x Port:0X%08x Pin:0X%08x IR_CallBack:0X%08x\r\n",__FUNCTION__,IR,Port,Pin,deal);
}

/*******************************************************************************
** 函数名称: IrScan
** 功能描述: 扫描，放入中断或者定时器中，输入时间单位为100us
** 参数说明: IR: [输入]      需要操作的IR对象
**			     NowTime: [输入] 将现在的时间输入
** 返回说明: None
** 创建人员: YCG
** 创建日期: 2018-12-14
********************************************************************************/
void IrScan(IR_struct* IR, uint32_t NowTime) {
    uint8_t PinValue = (LL_GPIO_ReadInputPort(IR->Port)&IR->Pin) ? HIGH : LOW;  //读取引脚的电压

    if(PinValue != IR->LastPinValue) {                   //判断是否跳变
        uint16_t LeadTime = NowTime - IR->LastTime;      //计算时间差
        IR->LastTime = NowTime;                          //更新目前的时间
        IR->LastPinValue = PinValue;                     //保留这一次的时间
			//  VS1838_Printf("%x %d\r\n", IR->State,LeadTime);      //打印当前的状态
        switch (IR->State)                    //判断目前接收状态
        {
        case IR_START:                        //信号开始状态
            if (PinValue == LOW)       //判断引脚的电压值
            {
                IR->Read.Re32 = 0;            // 状态清零
                IR->ReadBit = 0;              // 读取位清零
                IR->State = IR_START_L;       //进去下一次的状态
            }
            break;
        case IR_START_L:                      //检测起始低电平 可以用来判断编码类型
            if (PinValue == HIGH) {
                if(IsInRang(LeadTime, IRCode[IR_NEC].StartLowTime)) //判断编码类型，由起始低电平时间决定
                {
                    IR->Code  = &IRCode[IR_NEC];        //编码类型
                    IR->State =  IR_START_H;            //进去下一次的状态
                    break;
                }
                if(IsInRang(LeadTime, IRCode[IR_KANGJIA].StartLowTime)) //判断编码类型，由起始低电平时间决定
                {
                    IR->Code  = &IRCode[IR_KANGJIA];        //编码类型
                    IR->State =  IR_START_H;            //进去下一次的状态
                    break;
                }
            }
            IR->State = IR_START;                   //返回起始状态
            break;
        case IR_START_H:                    //检测起始高电平  用来判断是不是重复信号
            if (PinValue == LOW)
            {
                if(IsInRang(LeadTime, IR->Code->StartHighTime))   //第一次读取的起始高电平
                {
                    IR->State = IR_BEGIN;                         //进去读取数据状态
                    break;
                }
                if(IR->Code->type == IR_NEC) {
                    if(IsInRang(LeadTime, IR->Code->ReStartHighTime)                          //重复信号的的起始高电平
                            && IsInRang(NowTime - IR->LastReadTime, IR->Code->Ctime))  {  //重复信号时间间隔是否超时
                        IR->Read.Re32 = IR->LastRead;          //获取上一次的输出值
                        IR->State = IR_END;                           //直接输出结果
                        break;
                    }
                }
            }
            IR->State = IR_START;             //返回起始状态
            break;
        case IR_BEGIN:                            //检测每一位的开始
            if ((PinValue == HIGH) && IsInRang(LeadTime, IR->Code->BitLowTime))  //检测每个数据位的起始脉宽
            {
                if (IR->ReadBit < IR->Code->BitNum)             //判读需要读取的数据位数
                {
                    IR->State = IR_READ;                        //读取数据
                }
                else
                {
                    IR->State = IR_END;                         //读取数据完毕，输出结果
                }
                break;
            }
            IR->State = IR_START;        //接收错误，返回起始状态
            break;
        case IR_READ:                           //读取每一位的数据
            if (PinValue == LOW)
            {
                IR->Read.Re32  <<=  1;          //数据右移一位,腾出位置接收
                IR->ReadBit++;                  //读取计数加一
                IR->State = IR_BEGIN;           //进入下一次数据读取
                if(IsInRang(LeadTime, IR->Code->Bit1Time)) {
                    IR->Read.Re32 |= 0x0001;                 //读取数据1
                    break;
                }
                if(IsInRang(LeadTime, IR->Code->Bit0Time)) {
                    IR->Read.Re32 &= ~0x0001;                //读取数据0
                    break;
                }
            }
            IR->State = IR_START;                   //读取错误，返回起始状态
            break;
        case IR_END:                             //结束接收，数据处理 
            if(IR->Code->type == IR_NEC) {                         //NEC编码结果处理
                if( IR->Read.Re8[1] == (uint8_t)~IR->Read.Re8[0]) { //验证数据
                    IR->add = IR->Read.Re8[3];                 //输出地址
                    IR->dat = IR->Read.Re8[1];                 //输出数据
									VS1838_Printf("IR_NEC Add:0X%02x Dat:0X%02x\r\n",IR->add,IR->dat);
                    if(IR->DatDeal != NULL) {                  //确保函数地址不为空
                        IR->DatDeal(IR);
                    }
                }
            }
            if(IR->Code->type == IR_KANGJIA) {                        //NEC编码结果处理
                if((IsInRang(LeadTime, IR->Code->EndTime))               //检测结束时间
                        && (IsInRang(NowTime - IR->LastReadTime, IR->Code->Ctime))  //检测第二次按下
                        && (IR->LastRead == IR->Read.Re32)) { //校验前后两次数据是否相等
                    IR->add = IR->Read.Re8[1];                 //输出地址
                    IR->dat = IR->Read.Re8[0];                 //输出数据
													VS1838_Printf("IR_KANGJIA Add:0X%02x  Dat:0X%02x\r\n",IR->add,IR->dat);
                    if(IR->DatDeal != NULL) {                  //确保函数地址不为空
                        IR->DatDeal(IR);
                    }
                }
            }
            IR->LastRead = IR->Read.Re32;        //保存一下这次的结果，供重复触发时使用
            IR->LastReadTime = NowTime;          //保存这一次结果输出的时间
            IR->State = IR_START;                //返回起始状态
            break;
        }
    }
         //VS1838_Printf("%x", IR->State);      //打印当前的状态
}

/********************************End of File************************************/

